/*
 * KernelBasis.java
 *
 * Created on April 27, 2005, 11:37 AM
 */

package com.milowski.monos.binomial;

import java.io.*;
import java.util.*;
import java.math.BigInteger;

/**
 *
 * @author R. Alexander Milowski
 */
public class KernelBasis
{

   static KernelBasis defaultInstance = new KernelBasis();
   
   //protected String program = new File("ikernel").getAbsolutePath();
   protected String program = "ikernel";
   
   /** Creates a new instance of LLL */
   protected KernelBasis()
   {
   }
   
   public static KernelBasis getInstance() {
      return new KernelBasis();
   }
   
   public static KernelBasis getDefaultInstance() {
      return defaultInstance;
   }
/*
   
   public void setProgram(File path) {
      program = path.getAbsolutePath();
   }
*/
   
   public MatrixBasis compute(MatrixBasis matrix) {
      BigInteger [][] columns = new BigInteger[matrix.getColumnCount()][];
      for (int col=0; col<columns.length; col++) {
         columns[col] = new BigInteger[matrix.values.length];
         for (int i=0; i<matrix.values.length; i++) {
            columns[col][i] = BigInteger.valueOf(matrix.values[i][col]);
         }
      }
      return compute(columns);
   }
   
   public MatrixBasis compute(Matrix<BigInteger> matrix) {
      BigInteger [][] columns = new BigInteger[matrix.getNumberOfColumns()][];
      for (int col=0; col<columns.length; col++) {
         columns[col] = new BigInteger[matrix.getNumberOfRows()];
         for (int i=0; i<columns[col].length; i++) {
            columns[col][i] = matrix.get(i,col);
         }
      }
      return compute(columns);
   }
   
   public MatrixBasis compute(BigInteger [][] columns) {
      /*
      try {
         Process proc = Runtime.getRuntime().exec(program);
         OutputStream stream = proc.getOutputStream();
         matrix.write(stream);
         stream.close();
         InputStream input = proc.getInputStream();
         Reader rinput = new InputStreamReader(input);
         MatrixBasis basis = MatrixBasis.read(rinput);
         try {
            proc.waitFor();
         } catch (InterruptedException ex) {
            ex.printStackTrace();
            return null;
         }
         rinput.close();
         return basis;
      } catch (IOException ex) {
         ex.printStackTrace();
         return null;
      }*/
      BigInteger [][] bigBasis = LLL.relations(columns);
      if (bigBasis!=null) {
         int rowSize = bigBasis.length;
         int colSize = bigBasis[0].length;
         MatrixBasis basis = new MatrixBasis(rowSize,colSize);
         for (int row=0; row<rowSize; row++) {
            for (int col=0; col<colSize; col++) {
               if (bigBasis[row][col].bitLength()>15) {
                  throw new RuntimeException("Value cannot be stored in a short: "+bigBasis[row][col]);
               }
               basis.set(row,col,bigBasis[row][col].shortValue());
            }
         }
         return basis;
      } else {
         return null;
      }
   }
   
   public static void main(String [] args) {
      try {
         Reader input = args.length!=0 ? 
                           new FileReader(args[0]) :
                           new InputStreamReader(System.in);
         Matrix<BigInteger> matrix = new Matrix<BigInteger>();
         matrix.read(input,NumberConstructor.BIG_INTEGER);
         //MatrixBasis matrix = MatrixBasis.read(input);
         KernelBasis kbasis = KernelBasis.getDefaultInstance();
/*
         if (args.length!=0) {
            kbasis.setProgram(new File(args[0]));
         }
*/
         MatrixBasis kernelBasis = kbasis.compute(matrix);
         if (kernelBasis!=null) {
            kernelBasis.write(System.out);
         }
      } catch (IOException ex) {
         ex.printStackTrace();
      }
   }
   
}
